package bricks.controller;

import bricks.config.GameConstant;
import bricks.entity.Ball;
import bricks.entity.Brick;
import bricks.entity.Huge;
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.fxml.FXML;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.util.Duration;

import java.util.ArrayList;
import java.util.List;

public class GameController {

    @FXML
    private Canvas canvas;

    private GraphicsContext graphic;

    private Huge huge;

    private List<Brick> bricks;

    private Ball ball;

    private Timeline timeline;


    public void run(){
        timeline = new Timeline(new KeyFrame(Duration.millis(20),
                t -> this.showGame(graphic)));
        timeline.setCycleCount(Timeline.INDEFINITE);
        timeline.play();
    }


    @FXML
    public void initialize(){
        initGame();
        this.graphic = canvas.getGraphicsContext2D();
        this.canvas.requestFocus();
        this.canvas.setFocusTraversable(true);
        this.canvas.setOnKeyPressed(this::keyPressed);
        this.canvas.setOnMouseClicked(this::mouseClicked);
        run();
    }

    public void mouseClicked(MouseEvent event) {
        if (this.ball.isStart()) {
            return;
        }
        double x = event.getX();
        double y = event.getY();

        double ballX = this.ball.getX();
        double ballY = this.ball.getY();

        double tanAngle = Math.abs((x - ballX) / (y - ballY));
        if (x > ballX) {
            this.ball.setDirectionX(1);
        } else if (x < ballX) {
            this.ball.setDirectionX(-1);
        } else {
            this.ball.setDirectionX(0);
        }

        if (y > ballY) {
            this.ball.setDirectionY(1);
        } else if (y < ballY) {
            this.ball.setDirectionY(-1);
        } else {
            this.ball.setDirectionY(0);
        }
        double atan = Math.atan(tanAngle);
        this.ball.setSpeedX(5 * Math.sin(atan));
        this.ball.setSpeedY(5 * Math.cos(atan));
        this.ball.setStart(true);
    }

    private void keyPressed(KeyEvent event) {
        if (event.getCode() == KeyCode.LEFT) {
            if (this.huge.getX() <= 0) {
                this.huge.setX(0);
            } else {
                this.huge.setX(this.huge.getX() - 20);
            }
        } else if (event.getCode() == KeyCode.RIGHT) {
            if (this.huge.getX() >= 640 - this.huge.getWidth()) {
                this.huge.setX(640 - this.huge.getWidth());
            } else {
                this.huge.setX(this.huge.getX() + 20);
            }
        } else if (event.getCode() == KeyCode.SPACE) {
            if (timeline.getStatus() == Animation.Status.PAUSED) {
                timeline.play();
            } else if (timeline.getStatus() == Animation.Status.RUNNING) {
                timeline.pause();
            }
        }
    }

    private void initGame(){
        this.huge = new Huge((640 - GameConstant.HUGE_WIDTH) / 2, 400- GameConstant.HUGE_HEIGHT, GameConstant.HUGE_WIDTH, GameConstant.HUGE_HEIGHT);
        this.ball = new Ball((640 - GameConstant.BALL_WIDTH) / 2, 400- GameConstant.HUGE_HEIGHT - GameConstant.BALL_HEIGHT, GameConstant.BALL_WIDTH, GameConstant.BALL_HEIGHT);
        this.bricks = new ArrayList<>();
        for (int i = 0; i < 6; i++) {
            for (int j = 0; j < 10; j++) {
                this.bricks.add(new Brick(j * GameConstant.BRICK_WIDTH, i * GameConstant.BRICK_HEIGHT, GameConstant.BRICK_WIDTH, GameConstant.BRICK_HEIGHT));
            }
        }
    }

    private void showGame(GraphicsContext graph){
        graph.clearRect(0,0, 640, 400);
        if (this.ball.isLife()) {
            boolean win = true;
            for (Brick brick : this.bricks) {
                if (brick.isLife()) {
                    win = false;
                }
                this.ball.collideWith(brick);
                brick.draw(graphic);
            }
            if (win) {
                graph.setStroke(Color.GREEN);
                graph.setFont(Font.font(32));
                graph.strokeText("你 获 胜 了", 250, 200);
                return;
            }
            this.ball.setX(this.ball.getX() + this.ball.getSpeedX() * this.ball.getDirectionX());
            this.ball.setY(this.ball.getY() + this.ball.getSpeedY() * this.ball.getDirectionY());
            this.ball.collideWith(huge);
            this.huge.draw(graphic);
            this.ball.draw(graphic);
        } else {
            graph.setStroke(Color.RED);
            graph.setFont(Font.font(32));
            graph.strokeText("你 失 败 了", 250, 200);
        }

    }
}
